#include "Table.h"
#include <iostream>
#include <cstdio>

Table::Table() {
}

Table::Table(std::string tableName, std::vector<std::string> attr,
		std::map<std::string, int> defaul,
		std::vector<std::string> primaryKey) {
	ErrorType = Create(tableName, attr, defaul, primaryKey);
}

Table::~Table() {
}

// return 0 if no error occured.
int Table::ifHasError() {
	return ErrorType;
}

/** 
 * return 错误类型：
 * 1: 属性个数超过100
 * 2：属性有重复项
 * 3：primaryKey未在属性列表中出现
 */
int Table::Create(std::string tableName, std::vector<std::string> attr,
		std::map<std::string, int> defaul,
		std::vector<std::string> primaryKey) {
	if (attr.size() > 100) {
		return 1;
	}
	TableName = tableName;
	std::map<std::string, int> temp;
	for (int i = 0; i < attr.size(); i++) {
		temp[attr[i]]++;
		if (temp[attr[i]] > 1) {
			return 2;
		}
	}
	Attributes = attr;
	Defaul = defaul;
	for (int i = 0; i < primaryKey.size(); i++) {
		bool PrimaryAppeared = false;
		for (int j = 0; j < attr.size(); j++) {
			if (primaryKey[i] == attr[j])
				PrimaryAppeared = true;
		}
		if (!PrimaryAppeared) {
			return 3;
		}
	}
	PrimaryKey = primaryKey;
	return 0;
}

/** 
 * return 错误类型：
 * 1: primaryKey值的唯一性
 * 2：newRow中的每个属性是否在表中是否存在
 * 3: attribute存在重复
 * 4: attribute与value的个数不等
 */
int Table::Insert(std::vector<std::string> at, std::vector<int> values) {
	std::map<std::string, int> tempItems;

	if (at.size() != values.size()) {
		return 4;
	}

	std::map<std::string, int> temp;
	for (int i = 0; i < at.size(); i++) {
		temp[at[i]]++;
		if (temp[at[i]] > 1) {
			return 3;
		}
	}

	for (int i = 0; i < at.size(); i++) {
		tempItems[at[i]] = values[i];
	}

	for (int i = 0; i < Data.size(); i++) {
		int j;
		for (j = 0;
				j < PrimaryKey.size()
						&& tempItems[PrimaryKey[j]]
								== Data[i].items[PrimaryKey[j]]; j++) {
		}
		if (j == PrimaryKey.size()) {
			return 1;
		}
	}
	for (std::map<std::string, int>::iterator it = tempItems.begin();
			it != tempItems.end(); it++) {
		bool exists = false;
		for (int j = 0; j < Attributes.size(); j++) {
			if (it->first == Attributes[j]) {
				exists = true;
				break;
			}
		}
		if (!exists) {
			return 2;
		}
	}
	for (int i = 0; i < Attributes.size(); i++) {
		std::map<std::string, int>::iterator it = tempItems.find(Attributes[i]);
		if (it == tempItems.end()) {
			tempItems[Attributes[i]] = Defaul[Attributes[i]];
		}

	}
	Row newRow;
	newRow.items = tempItems;
	Data.push_back(newRow);
	return 0;
}

/** 
 * return 错误类型：
 * 本函数不反回1
 * 2: 判断属性不存在
 */
int Table::Delete(SyntaxTreeNode* condition) {
	if (condition == NULL) {
		std::cout << Data.size() << " rows ";
		Data.clear();
		return 0;
	}
	int deleteCount = 0;
	for (int i = 0; i < Data.size(); i++) {
		int result = conditionFitTheRow(condition, Data[i]);
		if (result == 0) { // if result == 0, then delete the row
			deleteCount++;
			Data.erase(Data.begin() + i);
			i--;
		} else if (result != 1) {
			return result;
		}
	}
	std::cout << deleteCount << " rows ";
	return 0;
}

/** 
 * return 错误类型：
 * 1: 选择属性不存在
 * 2：判断属性不存在
 */
int Table::Select(std::vector<std::string> AttributeList,
		SyntaxTreeNode* condition, bool selectAllAttr) {
	/* if '*' appeared, print all attributes*/
	if (selectAllAttr) {
		AttributeList = Attributes;
	}

	std::vector<Row> selectedData;

	/* see if there has error 1 */
	for (int i = 0; i < AttributeList.size(); i++) {
		bool AttriAppeared = false;
		for (int j = 0; j < Attributes.size(); j++) {
			if (AttributeList[i] == Attributes[j]) {
				AttriAppeared = true;
				break;
			}
		}
		if (!AttriAppeared) {
			return 1;
		}
	}

	/* if no condition, print all data */
	if (condition == NULL) {
		selectedData = Data;
	} else {
		/* selecte data */
		for (int i = 0; i < Data.size(); i++) {
			int result = conditionFitTheRow(condition, Data[i]);
			if (result == 0) {
				selectedData.push_back(Data[i]);
			} else if (result != 1) {
				return result;
			}
		}
	}

	/* print AttributeList*/
	for (int i = 0; i < AttributeList.size(); i++) {
		printf("|");
		for (int j = 0; j < AttributeList[i].size() + 10; j++) {
			printf("-");
		}
	}
	printf("|\n");
	for (int i = 0; i < AttributeList.size(); i++) {
		printf("|     %s     ", AttributeList[i].c_str());
	}
	printf("|\n");
	for (int i = 0; i < AttributeList.size(); i++) {
		printf("|");
		for (int j = 0; j < AttributeList[i].size() + 10; j++) {
			printf("-");
		}
	}
	printf("|\n");
	for (int i = 0; i < selectedData.size(); i++) {
		for (int j = 0; j < AttributeList.size(); j++) {
			int valueSize = 0, temp = selectedData[i].items[AttributeList[j]];
			while (temp != 0) {
				valueSize++;
				temp = temp / 10;
			}
			int spaceLeft = (AttributeList[j].size() + 10 - valueSize) / 2;
			int spaceRight = spaceLeft;
			if ((AttributeList[j].size() + 10 - valueSize) % 2 != 0) {
				spaceLeft++;
			}
			printf("|");
			for (int k = 0; k < spaceLeft; k++) {
				printf(" ");
			}
			printf("%d", selectedData[i].items[AttributeList[j]]);
			for (int k = 0; k < spaceRight; k++) {
				printf(" ");
			}
		}
		printf("|\n");
		for (int ii = 0; ii < AttributeList.size(); ii++) {
			printf("|");
			for (int jj = 0; jj < AttributeList[ii].size() + 10; jj++) {
				printf("-");
			}
		}
		printf("|\n");
	}
	std::cout << selectedData.size() << " rows ";
	return 0;
}

int Table::calculate(SyntaxTreeNode *equation, Row &row, int &Error) {
	if (Error) {
		return 0;
	}

	if (equation == NULL) {
		Error = 4;
		return 0;
	}

	int error = 0; // 0 means no error.
	int num1 =
			equation->getLeft() ?
					calculate(equation->getLeft(), row, error) : 0;
	int num2 =
			equation->getRight() ?
					calculate(equation->getRight(), row, error) : 0;

	if (error) {
		return 0;
	}

	std::string IdName = equation->getIdName();
	bool AttriAppeared = false;
	switch (equation->getType()) {
	case MUL:
		return num1 * num2;
		break;
    case DIV:
        if (num2 == 0) {
            Error = 7;
            return 0;
        }
		return num1 / num2;
		break;
	case PLUS:
		return num1 + num2;
		break;
	case MINUS:
		return num1 - num2;
		break;
	case NUM:
		return equation->getValue();
		break;
	case ID:
		/* some thing to write */
		for (int i = 0; i < Attributes.size(); i++) {
			if (IdName == Attributes[i]) {
				AttriAppeared = true;
				break;
			}
		}
		if (!AttriAppeared) {
			Error = 5;
			return 0;
		}
		return row.items[IdName];
		break;
	default:
		Error = 6;
	}
	return 0;
}

/**
 * return 0 means condition fit the row,
 * return 1 means condition don't fit the row,
 * 2 means error, the attributes don't exsits in table.
 * 3 bool sentence error
 * 4 Error in get equation.
 * 5 Error: 判断属性不存在.
 * 6 Error in equation calculate.
 * 7 Divided by Zero.
 */
int Table::conditionFitTheRow(SyntaxTreeNode *condition, Row &row) {
	if (condition == NULL) {
		return 3;
	}
	if (WHERE_CLAUSE == condition->getType()) {
		return conditionFitTheRow(condition->getLeft(), row);
	} else if (OR == condition->getType()) {
		int result1 = condition->getLeft() ? conditionFitTheRow(condition->getLeft(), row) : 1;
		int result2 = condition->getRight() ? conditionFitTheRow(condition->getRight(), row) : 1;
		if (result1 < 0 || result1 > 1 || result2 < 0 || result2 > 1) return result1 < 0 || result1 > 1 ? result1 : result2;		
		if (result1 == 0 || result2 == 0) return 0;
		else return 1;
	} else if (AND == condition->getType()) {
		int result1 =
				condition->getLeft() ?
						conditionFitTheRow(condition->getLeft(), row) : 0;
		int result2 =
				condition->getRight() ?
						conditionFitTheRow(condition->getRight(), row) : 0;
		if (!result1 && !result2) {
			return 0;
		} else if ((result1 == 0 || result1 == 1)
				&& (result2 == 0 || result2 == 1)) {
			return 1;
		} else if (result1 != 0 && result1 != 1) {
			return result1;
		} else {
			return result2;
		}
	} else if (BOOL == condition->getType()) {
		TokenType op = condition->getRight()->getType();
		int result; 
		if (op == BOOL || op == OR || op == AND) result = conditionFitTheRow(condition->getRight(), row);
		else {
			int error = 0; // 0 means no error.
			int num1 = calculate(condition->getRight()->getLeft(), row, error);
			int num2 = calculate(condition->getRight()->getRight(), row, error);
			if (error) {
				return error;
			}
			switch (op) {
			case LT:
				result = (num1 < num2);
				break;
			case LE:
				result = (num1 <= num2);
				break;
			case GT:
				result = (num1 > num2);
				break;
			case GE:
				result = (num1 >= num2);
				break;
			case EQ:
				result = (num1 == num2);
				break;
			case NEQ:
				result = (num1 != num2);
				break;
			default:
				return 3;
			}
			result = result ? 0 : 1; // Because we use 0 represents true, and 1 for false;
		}
		if (result != 0 && result != 1) return result;
		if (condition->getLeft() && NOT == condition->getLeft()->getType()) {
			return !result;
		} else {
			return result;
		}
	}
	return 3;
}
